Multithreading এবং Background Tasks

Mobile App Development - অ্যান্ড্রয়েড ডেভেলপমেন্ট (Android)
271

Android অ্যাপ্লিকেশনে Multithreading এবং Background Tasks ব্যবহার করে, আপনি জটিল কাজ বা ভারী প্রসেসিং অ্যাসিঙ্ক্রোনাসভাবে চালাতে পারেন, যাতে UI থ্রেড (Main Thread) ব্যস্ত না হয় এবং ব্যবহারকারী অভিজ্ঞতা প্রভাবিত না হয়। Android এ বিভিন্ন উপায়ে Multithreading এবং Background Tasks পরিচালনা করা যায়, যেমন Threads, AsyncTask, Handler, Executors, এবং WorkManager

Multithreading এবং Background Tasks

নিচে Multithreading এবং Background Tasks নিয়ে বিস্তারিত আলোচনা এবং উদাহরণ দেওয়া হলো:


১. Threads এবং Runnables

Android এ Thread ব্যবহার করে সোজা এবং সহজে Multithreading করা যায়। থ্রেডের মাধ্যমে নির্দিষ্ট কাজ ব্যাকগ্রাউন্ডে চালানো যায়।

উদাহরণ: Thread এবং Runnable

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        // এখানে ব্যাকগ্রাউন্ড টাস্ক সম্পন্ন করুন
        Log.d("BackgroundTask", "Task is running in background thread.");
    }
};

Thread thread = new Thread(runnable);
thread.start();

এই উদাহরণে, একটি Runnable তৈরি করা হয়েছে এবং এটি একটি নতুন থ্রেডে চালানো হয়েছে। এই পদ্ধতি সহজ হলেও থ্রেড ম্যানেজমেন্ট কিছুটা জটিল হতে পারে।


২. AsyncTask (Deprecated)

AsyncTask আগে ব্যাকগ্রাউন্ড টাস্ক পরিচালনা করার জন্য সাধারণত ব্যবহৃত হতো। এটি কিছু ভারী কাজ যেমন ডাটাবেজ অপারেশন বা নেটওয়ার্ক কল ব্যাকগ্রাউন্ডে চালাতে এবং তার রেজাল্ট UI তে আপডেট করতে সহায়ক। তবে এটি এখন Deprecated।

উদাহরণ: AsyncTask ব্যবহার করা

 

private class DownloadTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... urls) {
        // ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করুন
        return "Download Complete";
    }

    @Override
    protected void onPostExecute(String result) {
        // UI আপডেট করুন
        Log.d("AsyncTask", result);
    }
}

// AsyncTask চালু করা
new DownloadTask().execute("http://example.com/file");

 

নোট: AsyncTask এখন Deprecated কারণ এটি কিছু নির্দিষ্ট পরিস্থিতে অপ্রতুল এবং ভুলভাবে ব্যবহৃত হতে পারে, যা অ্যাপের কর্মক্ষমতা এবং স্থায়িত্বকে প্রভাবিত করতে পারে।


৩. Handler এবং Looper

Handler এবং Looper ব্যবহার করে আপনি মেসেজ এবং Runnable পরিচালনা করতে পারেন, যা আপনাকে নির্দিষ্ট থ্রেডে কাজ শিডিউল করতে দেয়।

উদাহরণ: Handler ব্যবহার করে মেসেজ পাঠানো

Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
    @Override
    public void run() {
        // UI থ্রেডে কাজ সম্পন্ন করুন
        Log.d("Handler", "Task is running on main thread.");
    }
});

এখানে Handler ব্যবহার করে UI থ্রেডে একটি কাজ শিডিউল করা হয়েছে।


৪. Executors এবং ExecutorService

Executors হল একটি API যা থ্রেড পরিচালনা এবং ব্যাকগ্রাউন্ড টাস্ক শিডিউল করার আরও ভালো এবং ফ্লেক্সিবল উপায় প্রদান করে।

উদাহরণ: Single Thread Executor ব্যবহার করা

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
    @Override
    public void run() {
        // ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করুন
        Log.d("Executor", "Task is running in single thread executor.");
    }
});

উদাহরণ: Fixed Thread Pool Executor ব্যবহার করা

ExecutorService executor = Executors.newFixedThreadPool(3);
executor.execute(new Runnable() {
    @Override
    public void run() {
        // একাধিক থ্রেডে কাজ সম্পন্ন করুন
        Log.d("Executor", "Task is running in fixed thread pool.");
    }
});

Executors বিভিন্ন ধরনের থ্রেড পুল তৈরি করতে দেয়, যা সহজেই একাধিক কাজ পরিচালনা করতে পারে।


৫. Coroutine (Kotlin)

Kotlin এ Coroutines একটি আধুনিক পদ্ধতি যা Multithreading এবং Background Tasks পরিচালনা করার জন্য ব্যবহৃত হয়। Coroutines আপনাকে লাইটওয়েট থ্রেড তৈরি এবং পরিচালনা করতে দেয়, যা কাজের জটিলতা অনেকাংশে কমিয়ে দেয়।

উদাহরণ: Coroutine ব্যবহার করা

GlobalScope.launch(Dispatchers.IO) {
    // ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করুন
    Log.d("Coroutine", "Task is running in coroutine.")
    
    withContext(Dispatchers.Main) {
        // UI আপডেট করুন
        Log.d("Coroutine", "Task is running on main thread.")
    }
}

Coroutine এ Dispatchers.IO ব্যবহার করে ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করা হয় এবং Dispatchers.Main ব্যবহার করে UI আপডেট করা হয়। এটি Android অ্যাপে Multithreading এর জন্য কার্যকরী একটি পদ্ধতি।


৬. WorkManager

WorkManager হল একটি ফ্লেক্সিবল এবং নির্ভরযোগ্য API যা ব্যাকগ্রাউন্ড টাস্ক যেমন ডেটা সিঙ্ক বা লোকেশন ট্র্যাকিং সম্পন্ন করতে ব্যবহৃত হয়। এটি বিশেষ করে তখন কার্যকর যখন অ্যাপটি ব্যাকগ্রাউন্ডে থাকে এবং নির্দিষ্ট সময়ে কাজ সম্পন্ন করতে হয়।

ধাপ ১: WorkManager লাইব্রেরি যোগ করা

implementation 'androidx.work:work-runtime:2.7.1'

ধাপ ২: WorkManager ব্যবহার করে ব্যাকগ্রাউন্ড টাস্ক তৈরি করা

public class UploadWorker extends Worker {
    public UploadWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করুন
        Log.d("WorkManager", "Task is running in WorkManager.");
        return Result.success();
    }
}

ধাপ ৩: কাজ শিডিউল করা

OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class).build();
WorkManager.getInstance(context).enqueue(uploadWorkRequest);

WorkManager একটি নির্ভরযোগ্য উপায় যা অ্যাপ্লিকেশন বন্ধ থাকলেও কাজ শিডিউল করতে পারে এবং এটি ব্যাটারি অপ্টিমাইজেশনের সাথে সামঞ্জস্যপূর্ণ।


৭. Best Practices

  • Avoid Long Tasks on Main Thread: Main Thread এ বড় কাজ বা ভারী প্রসেসিং করা উচিত নয়, কারণ এটি অ্যাপের রেসপন্সিভনেস কমিয়ে দেয়।
  • Use Executors or Coroutine for Complex Tasks: যদি কাজ জটিল হয়, তবে Executors বা Coroutines ব্যবহার করে ম্যানেজ করা সহজ।
  • WorkManager for Reliable Background Work: দীর্ঘস্থায়ী এবং নির্ভরযোগ্য কাজ যেমন ডেটা সিঙ্কের জন্য WorkManager ব্যবহার করা উচিত।
  • Proper Error Handling: থ্রেড বা ব্যাকগ্রাউন্ড টাস্ক ব্যবহারের সময় সঠিক Error Handling নিশ্চিত করা উচিত।
  • Avoid Deprecated APIs: AsyncTask এবং কিছু পুরোনো থ্রেডিং API এখন Deprecated, তাই এগুলো ব্যবহার এড়িয়ে চলা উচিত।

উপসংহার

Multithreading এবং Background Tasks ব্যবহারের মাধ্যমে Android অ্যাপ্লিকেশনে ভারী কাজ বা দীর্ঘস্থায়ী প্রসেসিং সম্পন্ন করা যায়, যাতে UI থ্রেড ব্যস্ত না হয় এবং অ্যাপ্লিকেশন রেসপন্সিভ থাকে। Android এ Threads, Executors, Coroutines, এবং WorkManager সহ বিভিন্ন উপায়ে এই কাজ করা যায়। সঠিক পদ্ধতি ব্যবহার করে এবং সঠিকভাবে কাজ পরিচালনা করে, আপনি একটি কার্যকরী এবং ব্যবহারবান্ধব অ্যাপ্লিকেশন তৈরি করতে সক্ষম হবেন।

Content added || updated By

AsyncTask ব্যবহার করে Background Tasks পরিচালনা

226

AsyncTask ব্যবহার করে Background Tasks পরিচালনা

Android অ্যাপ্লিকেশনে AsyncTask ব্যবহার করে ব্যাকগ্রাউন্ড টাস্ক সম্পন্ন করা যায়, যেমন নেটওয়ার্ক অপারেশন, ডাটাবেস অ্যাক্সেস, বা অন্যান্য লম্বা সময় ধরে চলা কাজ। AsyncTask মূলত ব্যাকগ্রাউন্ডে কাজ করে এবং কাজ শেষ হলে UI থ্রেডে রেজাল্ট আপডেট করে, যাতে অ্যাপ্লিকেশনটি রেসপন্সিভ থাকে এবং UI ব্লক না হয়।

AsyncTask এর মূল Components

AsyncTask ক্লাসটি তিনটি প্রধান জেনেরিক প্যারামিটার গ্রহণ করে:

  1. Params: ইনপুট প্যারামিটার, যা ব্যাকগ্রাউন্ড টাস্কে প্রেরণ করা হয়।
  2. Progress: ব্যাকগ্রাউন্ডে চলা টাস্কের স্ট্যাটাস (প্রগ্রেস আপডেটের জন্য)।
  3. Result: কাজের রেজাল্ট, যা কাজ শেষ হলে UI থ্রেডে পাঠানো হয়।

AsyncTask এ চারটি গুরুত্বপূর্ণ মেথড রয়েছে:

  • onPreExecute(): ব্যাকগ্রাউন্ড টাস্ক শুরু হওয়ার আগে UI থ্রেডে কল হয়।
  • doInBackground(Params...): ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করে (এই মেথডটি মেইন থ্রেডে কাজ করে না)।
  • onProgressUpdate(Progress...): প্রগ্রেস আপডেট করতে UI থ্রেডে কল হয়।
  • onPostExecute(Result): ব্যাকগ্রাউন্ড কাজ শেষ হওয়ার পর UI থ্রেডে কল হয় এবং রেজাল্ট প্রসেস করে।

AsyncTask এর উদাহরণ

নিচে একটি AsyncTask এর উদাহরণ দেওয়া হলো, যেখানে ব্যাকগ্রাউন্ডে কিছু ডেটা ফেচ করা হচ্ছে এবং কাজ শেষে UI আপডেট করা হচ্ছে।

MainActivity.java:

import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private TextView statusText;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        statusText = findViewById(R.id.statusText);
        progressBar = findViewById(R.id.progressBar);

        // AsyncTask শুরু করা
        new ExampleAsyncTask().execute(10); // এখানে ইনপুট প্যারামিটার হিসেবে ১০ পাঠানো হয়েছে
    }

    private class ExampleAsyncTask extends AsyncTask<Integer, Integer, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // কাজ শুরু হওয়ার আগে UI আপডেট করা
            statusText.setText("Task Started...");
            progressBar.setProgress(0);
        }

        @Override
        protected String doInBackground(Integer... params) {
            int maxCount = params[0]; // ইনপুট প্যারামিটার প্রাপ্তি
            for (int i = 1; i <= maxCount; i++) {
                try {
                    Thread.sleep(1000); // ১ সেকেন্ড ধরে কাজ করছে (সিমুলেশন)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                publishProgress((i * 100) / maxCount); // প্রগ্রেস আপডেট পাঠানো
            }
            return "Task Completed!";
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            // প্রগ্রেস আপডেট করা
            int progress = values[0];
            progressBar.setProgress(progress);
            statusText.setText("Progress: " + progress + "%");
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            // কাজ শেষ হওয়ার পর UI আপডেট করা
            statusText.setText(result);
        }
    }
}

Layout (activity_main.xml):

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/statusText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Status"
        android:textSize="18sp"/>

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0"
        android:indeterminate="false"/>

</LinearLayout>

কোডের ব্যাখ্যা:

  1. onPreExecute(): কাজ শুরু হওয়ার আগে UI থ্রেডে কল হয়। এখানে একটি প্রাথমিক স্ট্যাটাস এবং প্রগ্রেসবার সেট করা হয়েছে।
  2. doInBackground(): ইনপুট প্যারামিটার হিসেবে একটি ইন্টারেজার গ্রহণ করা হয়েছে, যা ব্যাকগ্রাউন্ডে প্রক্রিয়াকরণ করে। publishProgress() মেথডের মাধ্যমে প্রগ্রেস আপডেট পাঠানো হয়েছে।
  3. onProgressUpdate(): UI তে প্রগ্রেস আপডেট করা হয়েছে, যেমন প্রগ্রেসবার এবং টেক্সট ভিউ আপডেট করা।
  4. onPostExecute(): কাজ শেষ হওয়ার পর UI আপডেট করা হয়েছে এবং রেজাল্ট ডিসপ্লে করা হয়েছে।

AsyncTask ব্যবহার করার Best Practices

  1. ক্ষুদ্র কাজের জন্য AsyncTask ব্যবহার করা: AsyncTask শুধুমাত্র ক্ষুদ্র এবং দ্রুত সম্পন্ন করা যায় এমন কাজের জন্য ব্যবহার করা উচিত। বড় বা দীর্ঘমেয়াদি কাজের জন্য Executor বা WorkManager ব্যবহার করা ভালো।
  2. Context Leakage এড়ানো: AsyncTask ইনার ক্লাস হিসেবে ব্যবহার করার সময় এটি Activity বা Context এর উপর ডিপেন্ডেন্ট থাকে। Activity বা Context পরিবর্তন হলে মেমোরি লিক হতে পারে। এজন্য Static AsyncTask ব্যবহার করা ভালো।
  3. Lifecycle-aware না হওয়া: AsyncTask Android অ্যাপ্লিকেশনের লাইফসাইকেল ম্যানেজ করে না। তাই Activity ধ্বংস হয়ে গেলে AsyncTask চলতে থাকলে সমস্যা হতে পারে। এর পরিবর্তে Lifecycle-aware কম্পোনেন্ট (যেমন ViewModel, LiveData) ব্যবহার করা ভালো।
  4. Cancel করা: AsyncTask যখন আর প্রয়োজন নেই তখন cancel(true) ব্যবহার করে এটি বাতিল করা উচিত।

উপসংহার

AsyncTask হল Android এ ব্যাকগ্রাউন্ড টাস্ক পরিচালনা করার জন্য একটি সহজ এবং কার্যকরী পদ্ধতি। ছোট এবং দ্রুত কাজের জন্য এটি ব্যবহার করা ভালো, কিন্তু বড় কাজের জন্য বা ব্যাকগ্রাউন্ড টাস্ক ব্যবস্থাপনার জন্য WorkManager বা Executors এর মতো আধুনিক পদ্ধতি ব্যবহার করা ভালো। AsyncTask এর সঠিক ব্যবহার অ্যাপ্লিকেশনকে আরও রেসপন্সিভ এবং ইন্টারঅ্যাকটিভ করে তোলে।

Content added By

Handler এবং Looper এর মাধ্যমে Threads পরিচালনা

258

Android অ্যাপ্লিকেশনে Handler এবং Looper এর মাধ্যমে Threads পরিচালনা করা হয়। এগুলো Android এর Message Queue এবং Message Loop মেকানিজম ব্যবহার করে ব্যাকগ্রাউন্ড থ্রেডের কাজগুলি ম্যানেজ করতে সহায়ক। Handler এবং Looper একসাথে ব্যবহার করে আপনি মেইন থ্রেডের সাথে যোগাযোগ রাখতে এবং ব্যাকগ্রাউন্ড থ্রেডে বিভিন্ন টাস্ক এক্সিকিউট করতে পারেন। 

Handler এবং Looper এর মাধ্যমে Threads পরিচালনা

নিচে Handler এবং Looper নিয়ে বিস্তারিত আলোচনা এবং উদাহরণ দেওয়া হলো:


১. Looper কী?

Looper হল Android এর একটি ক্লাস, যা একটি থ্রেডের জন্য Message Loop বা Event Loop তৈরি করে। Looper একটি নির্দিষ্ট থ্রেডে একটি মেসেজ কিউ তৈরি করে এবং এটি সেই থ্রেডে মেসেজ বা রানেবল অবজেক্ট প্রসেস করতে দেয়। প্রতিটি Android অ্যাপ্লিকেশনের Main Thread (UI Thread) এর সাথে ডিফল্টভাবে একটি Looper থাকে।

Looper এর বৈশিষ্ট্য:

  • Looper একটি থ্রেডে মেসেজ কিউ তৈরি করে।
  • এটি একটি loop() মেথড ব্যবহার করে থ্রেডে একটি infinite loop চালায়, যা মেসেজ প্রসেস করে।
  • একটি quit() মেথড ব্যবহার করে Looper বন্ধ করা যায়।

২. Handler কী?

Handler হল একটি ক্লাস, যা Looper এর মাধ্যমে মেসেজ পাঠানো এবং রিসিভ করার জন্য ব্যবহার করা হয়। Handler সাধারণত থ্রেডের সাথে যুক্ত থাকে এবং সেই থ্রেডে মেসেজ পাঠানোর মাধ্যমে কাজ পরিচালনা করে।

Handler এর বৈশিষ্ট্য:

  • Handler এর মাধ্যমে একটি নির্দিষ্ট থ্রেডে মেসেজ বা রানেবল পাঠানো যায়।
  • এটি post(), postDelayed(), sendMessage() মেথড ব্যবহার করে কাজগুলি থ্রেডের মেসেজ কিউতে যোগ করে।
  • Handler মেসেজ রিসিভ করার পর handleMessage() মেথড ব্যবহার করে সেই মেসেজ প্রসেস করে।

৩. Handler এবং Looper এর মাধ্যমে Thread তৈরি এবং পরিচালনা করা

Handler এবং Looper ব্যবহার করে একটি কাস্টম থ্রেড তৈরি করা এবং সেটি পরিচালনা করা সহজ। নিচে এর উদাহরণ দেখানো হলো:

উদাহরণ: কাস্টম থ্রেডে Looper এবং Handler ব্যবহার

Step 1: একটি কাস্টম থ্রেড তৈরি করা

class MyCustomThread extends Thread {
    public Handler handler;

    @Override
    public void run() {
        // Looper প্রস্তুত করা
        Looper.prepare();

        // Handler তৈরি করা, যা এই থ্রেডের সাথে কাজ করবে
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // মেসেজ প্রসেস করা
                Log.d("HandlerMessage", "Received message: " + msg.what);
            }
        };

        // Looper শুরু করা
        Looper.loop();
    }
}

এখানে MyCustomThread ক্লাসে একটি Handler এবং Looper সেটআপ করা হয়েছে। Looper.prepare() মেথড Looper সেটআপ করে এবং Looper.loop() মেথড মেসেজ কিউ চালু করে। Handler এর handleMessage() মেথড মেসেজ প্রসেস করার জন্য ব্যবহার করা হয়েছে।

Step 2: থ্রেড শুরু করা এবং মেসেজ পাঠানো

MyCustomThread customThread = new MyCustomThread();
customThread.start();

// থ্রেড শুরু হওয়ার পর কিছু সময়ের জন্য অপেক্ষা করা, যাতে Looper প্রস্তুত হয়
new Handler(Looper.getMainLooper()).postDelayed(() -> {
    if (customThread.handler != null) {
        Message message = Message.obtain();
        message.what = 1;
        customThread.handler.sendMessage(message);
    }
}, 1000);

উপরের কোডে একটি MyCustomThread ইন্সট্যান্স তৈরি করা হয়েছে এবং start() মেথড ব্যবহার করে থ্রেড শুরু করা হয়েছে। মেইন থ্রেড থেকে ১ সেকেন্ড পর একটি মেসেজ কাস্টম থ্রেডের Handler এর মাধ্যমে পাঠানো হয়েছে।


৪. Main Thread (UI Thread) এর সাথে Handler ব্যবহার

Android অ্যাপ্লিকেশনে Main Thread বা UI Thread-এ কাজ করার জন্য Handler একটি গুরুত্বপূর্ণ ভূমিকা পালন করে। ব্যাকগ্রাউন্ড থ্রেড থেকে UI Thread-এ কাজ করতে Handler ব্যবহার করা হয়।

উদাহরণ: UI Thread এ ব্যাকগ্রাউন্ড থ্রেড থেকে কাজ করা

Handler mainHandler = new Handler(Looper.getMainLooper());

Thread backgroundThread = new Thread(() -> {
    try {
        // কিছু ব্যাকগ্রাউন্ড টাস্ক
        Thread.sleep(2000);
        
        // মেইন থ্রেডে কাজ পাঠানো
        mainHandler.post(() -> {
            // UI উপাদান আপডেট করা
            Log.d("UIUpdate", "UI Updated from background thread");
        });
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

backgroundThread.start();

এখানে mainHandler ব্যবহার করে UI Thread-এ ব্যাকগ্রাউন্ড থ্রেড থেকে কাজ পাঠানো হয়েছে। post() মেথডের মাধ্যমে Runnable UI Thread এ যোগ করা হয়েছে, যাতে UI উপাদান আপডেট করা যায়।


৫. HandlerThread: Handler এবং Looper এর সহজ ইমপ্লিমেন্টেশন

Android এ HandlerThread একটি বিশেষ থ্রেড, যা Looper এবং Handler ইন্টারনালি সেটআপ করে। এটি ব্যবহার করে একটি ব্যাকগ্রাউন্ড থ্রেডে কাজ সহজেই পরিচালনা করা যায়।

উদাহরণ: HandlerThread ব্যবহার

HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();

// Handler তৈরি করা, যা HandlerThread এর সাথে কাজ করবে
Handler backgroundHandler = new Handler(handlerThread.getLooper());

backgroundHandler.post(() -> {
    // ব্যাকগ্রাউন্ড কাজ করা
    Log.d("HandlerThread", "Running task in background thread");
});

HandlerThread ইন্সট্যান্স তৈরি করে, ব্যাকগ্রাউন্ড থ্রেডে Runnable পোস্ট করা হয়েছে। এটি Handler এবং Looper ম্যানুয়ালি সেটআপ করার চেয়ে সহজ এবং কার্যকর।


৬. Looper এর Lifecycle এবং থ্রেড বন্ধ করা

Looper চলমান রাখার জন্য একটি থ্রেড ইনফাইনিট লুপে কাজ করে। যখন থ্রেড বন্ধ করতে হবে, তখন Looper.quit() বা Looper.quitSafely() ব্যবহার করা হয়।

উদাহরণ: Looper বন্ধ করা

if (handlerThread != null) {
    handlerThread.quitSafely();
}

এখানে quitSafely() ব্যবহার করে Looper কে বন্ধ করা হয়েছে। এটি মেসেজ কিউতে থাকা বর্তমান কাজগুলো সম্পন্ন করে তারপর Looper বন্ধ করে।


৭. Handler এবং Looper এর ব্যবহারিক প্রয়োগ

Handler এবং Looper ব্যবহার করে আপনি বিভিন্ন ধরনের কাজ করতে পারেন, যেমন:

  • Background Task Management: ব্যাকগ্রাউন্ডে কাজ পরিচালনা করা।
  • UI Updates: ব্যাকগ্রাউন্ড থেকে মেইন থ্রেডে UI আপডেট পাঠানো।
  • Scheduled Tasks: নির্দিষ্ট সময় পর পর কাজ এক্সিকিউট করা।

উপসংহার

Handler এবং Looper Android এ থ্রেড ম্যানেজমেন্টের একটি গুরুত্বপূর্ণ অংশ, যা ব্যাকগ্রাউন্ড এবং UI থ্রেডের মধ্যে যোগাযোগ সহজ করে। Handler ব্যবহার করে মেসেজ এবং রানেবল প্রসেস করা যায়, এবং Looper থ্রেডে মেসেজ কিউ তৈরি করে। এই মেকানিজমের মাধ্যমে আপনি Android অ্যাপ্লিকেশনগুলিতে ব্যাকগ্রাউন্ড টাস্ক পরিচালনা এবং UI আপডেট করতে সক্ষম হবেন।

Content added By

Kotlin Coroutines ব্যবহার করে Multithreading

235

Kotlin Coroutines Android অ্যাপ্লিকেশনে Multithreading এবং Asynchronous Tasks পরিচালনা করার একটি আধুনিক এবং কার্যকর পদ্ধতি। Coroutines আপনাকে লাইটওয়েট থ্রেড তৈরি করতে এবং সহজেই ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করতে সহায়তা করে, যা অ্যাপ্লিকেশনকে রেসপন্সিভ রাখে এবং UI থ্রেডে লোড কমায়।

Kotlin Coroutines ব্যবহার করে Multithreading

নিচে Kotlin Coroutines ব্যবহার করে Multithreading এবং Background Tasks এর বিস্তারিত আলোচনা এবং উদাহরণ দেওয়া হলো:


১. Coroutines কি?

Coroutines হল একটি লাইটওয়েট থ্রেডিং মেকানিজম যা Async কাজ সম্পন্ন করতে সাহায্য করে। এটি suspend ফাংশন ব্যবহার করে কোড সাসপেন্ড করতে এবং রিজিউম করতে পারে, যা কাজের জটিলতা কমায় এবং কোড আরও পাঠযোগ্য করে তোলে। Coroutines ব্যাকগ্রাউন্ড টাস্ক ম্যানেজ করতে এবং UI থ্রেডকে ব্যস্ত রাখার জন্য উন্নত সমাধান প্রদান করে।


২. Coroutine লাইব্রেরি যোগ করা

Gradle ফাইলে Coroutines লাইব্রেরি যোগ করুন:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'

৩. Coroutine ব্যবহার করার বেসিক উদাহরণ

Kotlin Coroutines ব্যবহার করে একটি সহজ Async Task চালানো হলো:

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        delay(1000L) // ১ সেকেন্ড অপেক্ষা করে
        println("Hello from Coroutine")
    }
    println("Outside Coroutine")
}

এখানে launch ব্লক ব্যবহার করে একটি Coroutine চালানো হয়েছে এবং delay ফাংশন দিয়ে এটি ১ সেকেন্ডের জন্য সাসপেন্ড করা হয়েছে। runBlocking মূল থ্রেডকে ব্লক করে, যাতে Coroutine শেষ না হওয়া পর্যন্ত কোড এক্সিকিউশন অপেক্ষা করে।


৪. Coroutines Dispatcher: কাজের প্রকার অনুযায়ী থ্রেড নির্বাচন করা

Kotlin Coroutines এ, Dispatchers ব্যবহার করে Coroutine এর কাজ কোন থ্রেডে চলবে তা নির্ধারণ করা যায়।

(ক) Dispatchers.Main: UI কাজের জন্য

UI কাজ এবং UI আপডেটের জন্য Dispatchers.Main ব্যবহার করা হয়। এটি Main Thread এ কাজ সম্পন্ন করে।

GlobalScope.launch(Dispatchers.Main) {
    // UI আপডেট বা কাজ সম্পন্ন করুন
    textView.text = "Updated Text"
}

(খ) Dispatchers.IO: I/O কাজের জন্য

নেটওয়ার্ক কল, ফাইল অপারেশন বা ডেটাবেজ কাজের জন্য Dispatchers.IO ব্যবহার করা হয়।

GlobalScope.launch(Dispatchers.IO) {
    val data = fetchDataFromNetwork()
    withContext(Dispatchers.Main) {
        // UI আপডেট করুন
        textView.text = data
    }
}

withContext(Dispatchers.Main) ব্যবহার করে, Coroutine কে UI থ্রেডে নিয়ে আসা হয়েছে, যাতে UI আপডেট করা যায়।

(গ) Dispatchers.Default: CPU-নিবিড় কাজের জন্য

কমপ্লেক্স এবং CPU-নিবিড় কাজ যেমন ডেটা প্রসেসিং বা অ্যালগরিদম চালানোর জন্য Dispatchers.Default ব্যবহার করা হয়।

GlobalScope.launch(Dispatchers.Default) {
    val result = heavyComputation()
    println("Computation result: $result")
}

৫. Suspend ফাংশন: Coroutine এর মূল ভিত্তি

Suspend ফাংশন Coroutine এর ভিতরে ব্যবহার করা হয় এবং এটি ব্যাকগ্রাউন্ডে কাজ সম্পন্ন করতে সাহায্য করে। Suspend ফাংশন Coroutine এর বাইরে ডিরেক্টলি কল করা যায় না।

উদাহরণ: Suspend ফাংশন তৈরি করা

suspend fun fetchDataFromNetwork(): String {
    delay(2000L) // ২ সেকেন্ড অপেক্ষা করে
    return "Data from network"
}

Suspend ফাংশন Coroutine এর মধ্যে ব্যবহার করা

GlobalScope.launch(Dispatchers.IO) {
    val data = fetchDataFromNetwork()
    withContext(Dispatchers.Main) {
        textView.text = data
    }
}

এখানে fetchDataFromNetwork() ফাংশনটি Coroutine এর ভিতরে কল করা হয়েছে, যা ২ সেকেন্ড অপেক্ষা করে এবং তারপর ডেটা রিটার্ন করে।


৬. CoroutineScope এবং GlobalScope

Kotlin Coroutines এ CoroutineScope ব্যবহার করে Coroutine এর জীবনকাল এবং নিয়ন্ত্রণ নির্ধারণ করা যায়।

  • GlobalScope: এটি অ্যাপ্লিকেশনের লং-লিভড Coroutine তৈরি করে, তবে এটি ব্যবহারে সতর্ক থাকতে হয় কারণ এটি মেমরি লিক সৃষ্টি করতে পারে।
  • CoroutineScope: এটি একটি নির্দিষ্ট কাজ বা লাইফসাইকেলের সাথে বাঁধা থাকে, যা মেমরি এবং রিসোর্স ম্যানেজমেন্টে সাহায্য করে।

উদাহরণ: CoroutineScope ব্যবহার করা

class MyActivity : AppCompatActivity(), CoroutineScope {

    private lateinit var job: Job

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        job = Job()
        launch {
            val data = fetchDataFromNetwork()
            textView.text = data
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        job.cancel() // কাজটি বাতিল করা
    }

    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job
}

এখানে CoroutineScope ব্যবহার করে, Coroutine এর লাইফসাইকেল Activity এর সাথে বাঁধা হয়েছে, যাতে Activity ধ্বংস হলে Coroutine বাতিল হয়ে যায়।


৭. Coroutines এবং Exception Handling

Coroutine এর মধ্যে Exception Handling গুরুত্বপূর্ণ। Exception এর মাধ্যমে আপনার Coroutine যদি ব্যর্থ হয়, তাহলে আপনি সেটিকে হ্যান্ডেল করতে পারেন।

GlobalScope.launch(Dispatchers.IO) {
    try {
        val data = fetchDataFromNetwork()
        withContext(Dispatchers.Main) {
            textView.text = data
        }
    } catch (e: Exception) {
        Log.e("Coroutine", "Error fetching data", e)
    }
}

এখানে try-catch ব্যবহার করে Exception Handling করা হয়েছে, যাতে কোনো ত্রুটি ঘটলে সেটি লোগিং হয়।


৮. Coroutines এবং Lifecycle-Aware কাজ

Android এ lifecycleScope এবং viewModelScope ব্যবহার করে আপনি Coroutine তৈরি করতে পারেন, যা Lifecycle এবং ViewModel এর সাথে সামঞ্জস্যপূর্ণ এবং মেমরি অপ্টিমাইজেশনে সহায়ক।

উদাহরণ: lifecycleScope ব্যবহার করা

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleScope.launch {
            val data = fetchDataFromNetwork()
            textView.text = data
        }
    }
}

উদাহরণ: viewModelScope ব্যবহার করা

class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            val data = fetchDataFromNetwork()
            _data.postValue(data)
        }
    }
}

উপসংহার

Kotlin Coroutines একটি আধুনিক এবং কার্যকর উপায়, যা Android অ্যাপ্লিকেশনে Multithreading এবং Background Tasks পরিচালনা করতে সহজ করে তোলে। Dispatchers, Suspend Functions, এবং CoroutineScope ব্যবহার করে আপনি সহজেই ব্যাকগ্রাউন্ড কাজ চালাতে এবং UI আপডেট করতে পারেন। Lifecycle-aware Coroutines (lifecycleScope, viewModelScope) ব্যবহার করে, মেমরি অপ্টিমাইজেশনের সাথে সমন্বয় রেখে কার্যকর অ্যাপ্লিকেশন তৈরি করা সম্ভব।

Content added || updated By

WorkManager দিয়ে Background Tasks পরিচালনা

278

WorkManager দিয়ে Background Tasks পরিচালনা

WorkManager হল Android এ ব্যাকগ্রাউন্ড টাস্ক সম্পন্ন করার একটি শক্তিশালী এবং নির্ভরযোগ্য API, যা বিশেষভাবে দীর্ঘস্থায়ী এবং নির্ধারিত কাজের জন্য ব্যবহৃত হয়। এটি এমন টাস্ক ম্যানেজ করতে ব্যবহৃত হয়, যা নির্দিষ্ট শর্ত পূরণ হলে (যেমন নেটওয়ার্ক অ্যাক্সেস, ডিভাইস চার্জিং) সম্পন্ন করতে হয়। WorkManager এমন কাজের জন্য আদর্শ, যেগুলি অ্যাপ ক্লোজ হওয়ার পরেও চলতে থাকে এবং অ্যাপ রিস্টার্টের পরেও কাজ করে।


WorkManager এর প্রধান বৈশিষ্ট্য

  1. Reliable Execution: WorkManager নির্ভরযোগ্যভাবে কাজ সম্পন্ন করে, এমনকি ডিভাইস রিস্টার্টের পরেও।
  2. Chainable Work: আপনি একাধিক কাজ একে অপরের সাথে চেইন করতে পারেন, অর্থাৎ এক কাজ শেষ হলে আরেক কাজ শুরু হবে।
  3. Constraints: WorkManager কাজ সম্পন্ন করার জন্য নির্দিষ্ট শর্তাবলী সেট করতে দেয়, যেমন নেটওয়ার্ক কানেকশন, ডিভাইস চার্জিং।
  4. Lifecycle-aware: WorkManager Android Lifecycle এর সাথে সামঞ্জস্যপূর্ণ, তাই এটি নিরাপদ এবং উন্নত পারফরম্যান্স প্রদান করে।

WorkManager সেটআপ করা

WorkManager ব্যবহার করতে হলে নিচের ধাপগুলো অনুসরণ করতে হবে।

ধাপ ১: গ্রেডেল ডিপেন্ডেন্সি যোগ করা

build.gradle (Module: app) ফাইলে WorkManager এর ডিপেন্ডেন্সি যোগ করতে হবে:

dependencies {
    implementation "androidx.work:work-runtime:2.8.1"
}

ধাপ ২: Worker ক্লাস তৈরি করা

WorkManager এ ব্যাকগ্রাউন্ড টাস্ক পরিচালনা করতে একটি Worker ক্লাস তৈরি করতে হবে। Worker ক্লাসে আপনি আপনার কাজের লজিক ইমপ্লিমেন্ট করবেন।

ExampleWorker.java:

import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class ExampleWorker extends Worker {

    public ExampleWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        // ব্যাকগ্রাউন্ড কাজের লজিক
        Log.d("ExampleWorker", "Background work is running");

        // কাজের শেষে Result রিটার্ন করা
        return Result.success();
    }
}

ধাপ ৩: Worker শিডিউল করা

MainActivity.java:

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button startWorkButton = findViewById(R.id.startWorkButton);

        startWorkButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // OneTimeWorkRequest তৈরি করা
                OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(ExampleWorker.class).build();

                // WorkManager এর মাধ্যমে কাজ শুরু করা
                WorkManager.getInstance(getApplicationContext()).enqueue(workRequest);
            }
        });
    }
}

Layout (activity_main.xml):

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <Button
        android:id="@+id/startWorkButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Work"/>
</LinearLayout>

কোডের ব্যাখ্যা:

  1. Worker: ExampleWorker ক্লাসে doWork() মেথডে ব্যাকগ্রাউন্ড টাস্কের লজিক ইমপ্লিমেন্ট করা হয়েছে। এটি একটি ব্যাকগ্রাউন্ড থ্রেডে চলে এবং কাজের শেষে Result.success() রিটার্ন করে।
  2. WorkRequest: OneTimeWorkRequest একটি একবার চলা টাস্কের জন্য ব্যবহৃত হয়। আপনি যদি নির্দিষ্ট শর্তে বা পুনরাবৃত্তিমূলক কাজ চান, তাহলে PeriodicWorkRequest ব্যবহার করতে পারেন।
  3. WorkManager: WorkManager API ব্যবহার করে WorkRequest শুরু করা হয়েছে।

ধাপ ৪: Constraints এবং InputData যোগ করা

আপনি WorkManager এ কাজ সম্পন্ন করার জন্য নির্দিষ্ট শর্ত (Constraints) যোগ করতে পারেন। উদাহরণস্বরূপ, নেটওয়ার্ক অ্যাক্সেস এবং ডিভাইস চার্জিং কন্ডিশন যোগ করা:

import androidx.work.Constraints;
import androidx.work.NetworkType;

Constraints constraints = new Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresCharging(true)
        .build();

OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(ExampleWorker.class)
        .setConstraints(constraints)
        .build();

ধাপ ৫: Periodic Work সেট করা

কিছু কাজ বারবার চালানোর জন্য PeriodicWorkRequest ব্যবহার করা হয়:

import androidx.work.PeriodicWorkRequest;
import java.util.concurrent.TimeUnit;

PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(ExampleWorker.class, 15, TimeUnit.MINUTES)
        .setConstraints(constraints)
        .build();

WorkManager.getInstance(getApplicationContext()).enqueue(periodicWorkRequest);

Note: PeriodicWorkRequest সর্বনিম্ন ১৫ মিনিটের জন্য শিডিউল করা যায়। ১৫ মিনিটের কম সময়ের জন্য পুনরাবৃত্তিমূলক কাজ শিডিউল করা যায় না।

WorkManager এর Best Practices

  1. Lifecycle-aware কাজ: WorkManager ব্যাকগ্রাউন্ড টাস্ককে Lifecycle-aware করে তোলে, তাই এটি Activity বা Fragment ধ্বংস হলে কাজ চালিয়ে যেতে পারে।
  2. কাজ Cancel করা: WorkManager এর মাধ্যমে চলমান কাজ সহজে cancel করা যায়:
WorkManager.getInstance(getApplicationContext()).cancelWorkById(workRequest.getId());
  1. চেইনিং: WorkManager এর মাধ্যমে একাধিক কাজ একে অপরের পরপর (চেইনিং) বা প্যারালেলে চালানো যায়।
WorkManager.getInstance(getApplicationContext())
    .beginWith(workRequest1)
    .then(workRequest2)
    .enqueue();
  1. Constraints ব্যবহার: ডিভাইসের অবস্থা (যেমন নেটওয়ার্ক কানেকশন, চার্জিং) অনুযায়ী কাজ শিডিউল করা।

WorkManager এর সুবিধা

সুবিধাবিস্তারিত
Reliable Executionডিভাইস রিস্টার্টের পরেও কাজ সম্পন্ন হয়।
Lifecycle-awareকাজ অ্যাপ্লিকেশনের লাইফসাইকেল অনুযায়ী পরিচালনা হয়।
Chaining এবং Constraintsএকাধিক কাজ চেইন করা এবং নির্দিষ্ট শর্তে কাজ করা।
API CompatibilityWorkManager পুরোনো API লেভেলগুলোতেও কাজ করে।

উপসংহার

WorkManager হল Android এ ব্যাকগ্রাউন্ড টাস্ক সম্পন্ন করার একটি নির্ভরযোগ্য এবং কার্যকরী পদ্ধতি। এটি নির্দিষ্ট শর্ত এবং লাইফসাইকেল ম্যানেজমেন্টের সাথে ব্যাকগ্রাউন্ড কাজ চালানোর জন্য উপযুক্ত। বড় বা দীর্ঘস্থায়ী কাজের জন্য WorkManager AsyncTask এর চেয়ে বেশি কার্যকর, কারণ এটি ডিভাইস রিস্টার্টের পরেও কাজ চালিয়ে যেতে পারে এবং ব্যাকগ্রাউন্ডে কাজ নির্ভরযোগ্যভাবে সম্পন্ন করে।

Content added By
Promotion
NEW SATT AI এখন আপনাকে সাহায্য করতে পারে।

Are you sure to start over?

Loading...